import math

def FromRGB(r,g,b):
    return CIELab.FromRGB(r,g,b)

class CIELab:
    def __init__(self,L,a,b):
        self.L=L
        self.A=a
        self.B=b
    
    @staticmethod
    def FromRGB(r,g,b):
        xyz=CIExyz.FromRGB(r,g,b)
        lab=xyz.ToLab()
        del xyz
        return lab
    
    def ToRGB(self):
        xyz=CIExyz.FromLab(self)
        rgb=xyz.ToRGB()
        del xyz
        return rgb

class CIExyz:
    def __init__(self,x,y,z):
        self.x=0.9505 if x>0.9505 else (0 if x<0 else x)
        self.y=1.0 if y>1.0 else (0 if y<0 else y)
        self.z=1.089 if z>1.089 else (0 if z<0 else z)
        
    @staticmethod
    def FromRGB(r,g,b):
        tmp=[pow((x+0.055)/1.055,2.2) if x>0.04045 else x/12.92 for x in (r/255.0,g/255.0,b/255.0)]
        
        return CIExyz(
            tmp[0]*0.4124+tmp[1]*0.3576+tmp[2]*0.1805
            ,tmp[0]*0.2126+tmp[1]*0.7152+tmp[2]*0.0722
            ,tmp[0]*0.0193+tmp[1]*0.1192+tmp[2]*0.9505
        )
    
    def ToRGB(self):
        cLinear=(12.92*x if x<=0.0031308 else 1.055*pow(x,1.0/2.4)-0.055 for x in (
            self.x*3.2410 - self.y*1.5374 - self.z*0.4986
            ,-self.x*0.9692 + self.y*1.8760 - self.z*0.0416
            ,self.x*0.0556 - self.y*0.2040 + self.z*1.0570
        ))
        rgbtmp=(int(x*255.0) for x in cLinear)
        return [255 if c>255 else (0 if c<0 else c) for c in rgbtmp]
    
    @staticmethod
    def __Fxyz(t):
        return pow(t, (1.0/3.0)) if t > 0.008856 else (7.787*t + 16.0/116.0)
    
    @staticmethod
    def FromLab(lab):
        th=6.0/29.0;
        tmp=[0,(lab.L+16)/116.0,0]
        tmp[0]=tmp[1]+(lab.A/500.0);
        tmp[2]=tmp[1]-(lab.B/200.0);
        
        tmp2=[x*x*x if x>th else (x-16.0/116.0)*3*th*th for x in tmp]
        
        return CIExyz(
            tmp2[0]*0.9505
            ,tmp2[1]*1.0
            ,tmp2[2]*1.0890
        )
    
    def ToLab(self):
        return CIELab(
            116.0*self.__Fxyz(self.y/1.0) -16
            ,500.0*(self.__Fxyz(self.x/0.9505) - self.__Fxyz(self.y/1.0))
	    ,200.0*(self.__Fxyz(self.y/1.0) - self.__Fxyz(self.z/1.089))
        )

if __name__=="__main__":
    __redLab=CIELab.FromRGB(255,0,0)
    print __redLab.L,redLab.A,redLab.B
    print __redLab.ToRGB()